package com.melodyframe.common.tools.bean;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * A tool for operate property of bean
 * 
 * @author ettear
 * 
 */
public class BeanPropertyUtil {
	/**
	 * Get the property name from method (such as getter or setter)
	 * 
	 * @param methodName
	 *            The name of method
	 * @return The name of property
	 */
	public static String getPropertyNameFromMethod(String methodName) {
		StringBuilder propertyNameBuilder = new StringBuilder();
		propertyNameBuilder.append(methodName.substring(3, 4).toLowerCase());
		if (methodName.length() > 4) {
			propertyNameBuilder.append(methodName.substring(4));
		}
		return propertyNameBuilder.toString();
	}

	/**
	 * Get the type of method (gettor, setter or others)
	 * 
	 * @param methodName
	 *            The name of method
	 * @return The type of method
	 */
	public static PropertyMethodType getPropertyMethodType(String methodName) {
		if (methodName.length() > 3) {
			if (methodName.substring(0, 3).equals("get")) {
				return PropertyMethodType.GETTER;
			} else if (methodName.substring(0, 3).equals("set")) {
				return PropertyMethodType.SETTER;
			}
		}
		return PropertyMethodType.COMMON;
	}

	/**
	 * Get all properties of bean which can be change value
	 * 
	 * @param beanClass
	 *            The class of bean
	 * @return The list of writeable property
	 */
	public static List<PropertyEntry<?>> getWriteableProperties(
			Class<?> beanClass) {
		List<PropertyEntry<?>> properties = new ArrayList<PropertyEntry<?>>();
		Method[] methods = beanClass.getMethods();
		for (Method method : methods) {
			if (PropertyMethodType.SETTER == getPropertyMethodType(method
					.getName())) {
				PropertyEntry<?> property = getWriteableProperty(method);
				properties.add(property);
			}
		}
		return properties;
	}

	@SuppressWarnings({ "unchecked" })
	private static <T> PropertyEntry<T> getWriteableProperty(Method method) {
		String methodName = method.getName();
		Class<?>[] parameterTypes = method.getParameterTypes();
		if (parameterTypes.length == 1) {
			Class<?> propertyType = parameterTypes[0];

			PropertyEntry<T> propertyEntry = new PropertyEntry<T>();
			propertyEntry.setType((Class<T>) propertyType);
			propertyEntry.setName(getPropertyNameFromMethod(methodName));
			propertyEntry.setSetter(method);
			return propertyEntry;
		} else {
			return null;
		}
	}
}
